﻿/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "Widget.h"
#include "../base/InputEventDispatcher.h"
#include "../base/Debuger.h"
#include "../ui/UiCore.h"
#include "../base/EventListenerMouse.h"
#include "../base/EventFocus.h"
#include "../base/EventWidgetMove.h"
#include "../base/EventWidgetActive.h"
#include "../base/EventResize.h"
#include "../win32/ApplicationView.h"
#include "../base/EventMouse.h"
#include "../base/WidgetEvent.h"
#include "../base/EventKey.h"
#include "../base/CharacterEvent.h"
#include "../action/ActionManager.h"
#include "../base/GameWorld.h"
#include "Scale9Image.h"

#include <algorithm>

#define LISTENER_CALL(func,arg) \
	if(func){func(arg);}  

namespace SkyEngine2d
{

	Widget::Widget(Widget* parent /*= nullptr*/)
		: Object<Widget>(parent)
		, m_isEnabled(true)
		, m_isMouseTracking(false)
		, m_isDistributeCapturedInputs(false)
		, m_hasFocus(false)
		, m_focusPolicy(FocusPolicy::ClickFocus)
		, m_widgetState(WidgetState::Normal)
		, m_isVisible(true)
		, m_uiCore(nullptr)
		, m_camera(nullptr)
	{
		m_uiCore = UiCore::getInstance();
		if (parent)
		{
			m_camera = parent->getCamera();
		}
		else
		{
			m_camera = m_uiCore->getDefaultCamera();
			m_parent = m_uiCore->getDefaultWidget();
		}
	}


	void Widget::onKeyPressEvent(EventKey* event)
	{

	}

	void Widget::onKeyReleaseEvent(EventKey* event)
	{

	}

	void Widget::onMousePressEvent(EventMouse* event)
	{
		this->setCurrentWidgetState(WidgetState::Pressed);

		if (m_focusPolicy == FocusPolicy::ClickFocus)
		{
			captureFocus();
		}

		LISTENER_CALL(m_mousePressEventCall, event)
	}

	void Widget::onMouseReleaseEvent(EventMouse* event)
	{
		this->setCurrentWidgetState(m_lastWidgetState);
		LISTENER_CALL(m_mouseReleaseEventCall, event);
	}

	void Widget::onMouseMoveEvent(EventMouse* event)
	{
		LISTENER_CALL(m_mouseMoveEventCall, event);
		event->accept();
	}

	void Widget::onMouseDoubleClickedEvent(EventMouse* event)
	{
		LISTENER_CALL(m_mouseDoubleClickedEventCall, event);
	}

	void Widget::onMouseLeavesEvent(WidgetEvent* event)
	{
		this->setCurrentWidgetState(WidgetState::Normal);
		event->accept();
	}

	void Widget::onMouseEnterEvent(WidgetEvent* event)
	{
		this->setCurrentWidgetState(WidgetState::Hover);
		event->accept();
	}

	void Widget::onFocusInEvent(EventFocus* event)
	{
	}

	void Widget::onFocusOutEvent(EventFocus* event)
	{
	}

	void Widget::onCharacterEvent(EventCharacter* e)
	{
	}


	void Widget::onMoveEvent(EventWidgetMove* e)
	{

	}

	void Widget::onActiveEvent(EventWidgetActive* e)
	{
		m_isActive = true;
	}

	void Widget::onDeactiveEvent(EventWidgetActive* e)
	{
		m_isActive = false;
		//触发失去焦点的事件
		//EventFocus event;
		//this->onFocusOutEvent(&event);
	}

	void Widget::onResizeEvent(EventResize* e)
	{
		//更新背景图片的绘制大小
		for (const auto& info : m_styleInfoArr)
		{
			if (info && info->backgroundImage)
			{
				info->backgroundImage->setDisplaySize(e->getNewSize());
			}
		}
	}

	bool Widget::onEvent(IEvent* e)
	{
		if (!this->isEnabled())
		{
			goto end;
		}

		auto type = e->getType();
		switch (type)
		{
		case IEvent::Type::EventType_Mouse:
		{
			auto p = dynamic_cast<EventMouse*>(e);
			if (p)
			{
				auto t = p->getMouseEventType();
				switch (t)
				{
				case EventMouse::MouseEventType::None:
					break;
				case EventMouse::MouseEventType::Down:
					this->onMousePressEvent(p);
					break;
				case EventMouse::MouseEventType::Up:
					this->onMouseReleaseEvent(p);
					break;
				case EventMouse::MouseEventType::Move:
					this->onMouseMoveEvent(p);
					break;
				case EventMouse::MouseEventType::Scroll:
					break;
				case EventMouse::MouseEventType::DoubleDown:
					this->onMouseDoubleClickedEvent(p);
					break;
				}
			}
		}
		break;
		case IEvent::Type::EventType_Keyboard:
		{
			auto p = dynamic_cast<EventKey*>(e);
			if (p)
			{
				auto t = p->getKeyEventType();
				if (t == EventKey::Type::KeyPress)
				{
					this->onKeyPressEvent(p);
				}
				else if (t == EventKey::Type::KeyRelease)
				{
					this->onKeyReleaseEvent(p);
				}
			}
		}
		break;
		case IEvent::Type::EventType_Character:
		{
			auto p = dynamic_cast<EventCharacter*>(e);
			if (p)
			{
				this->onCharacterEvent(p);
			}
		}
		break;
		case IEvent::Type::EventType_WidgetFocus:
		{
			auto p = dynamic_cast<EventFocus*>(e);
			if (p)
			{
				auto t = p->getFouceEventType();
				if (t == EventFocus::EventType::FocusIn)
				{
					this->onFocusInEvent(p);
				}
				else if (t == EventFocus::EventType::FocusOut)
				{
					this->onFocusInEvent(p);
				}
			}
		}
		break;
		case IEvent::Type::EventType_WidgetMove:
		{
			auto p = dynamic_cast<EventWidgetMove*>(e);
			if (p)
			{
				this->onMoveEvent(p);
			}
		}
		break;
		case IEvent::Type::EventType_WidgetActive:
		{
			auto p = dynamic_cast<EventWidgetActive*>(e);
			if (p)
			{
				p->getActiveWidget()->onActiveEvent(p);
				p->getDeactiveWidget()->onDeactiveEvent(p);
			}
		}
		break;
		case IEvent::Type::EventTYpe_WidgetResize:
		{
			auto p = dynamic_cast<EventResize*>(e);
			if (p)
			{
				this->onResizeEvent(p);
			}
		}
		break;
		case IEvent::Type::EventType_EnterWidget:
		{
			WidgetEvent* p = dynamic_cast<WidgetEvent*>(e);
			if (p)
			{
				this->onMouseEnterEvent(p);
			}
		}
		break;
		case IEvent::Type::EventType_LeaveWIdget:
		{
			WidgetEvent* p = dynamic_cast<WidgetEvent*>(e);
			if (NULL != p)
			{
				this->onMouseLeavesEvent(p);
			}
		}
		break;

		}

	end:
		if (e->isAccept())
		{
			return true;
		}
		else
		{
			if (m_parent)
			{
				return m_parent->onEvent(e);
			}
			return false;
		}
	}

	void Widget::onWidgetStateChange()
	{

	}

	void Widget::onWidgetStyleChange()
	{

	}

	int Widget::getDefultWidth() const
	{
		return 150;
	}

	int Widget::getDefultHeight() const
	{
		return 100;
	}

	const std::unique_ptr<Widget::StyleInfor>& Widget::getStyleInfoPtr(WidgetState state)
	{
		int index = (int)state;
		DebugerAssert(index < Widget::WidgetStateCount, "状态值超过状态总数");
		const auto& p = m_styleInfoArr[index];
		if (!p)
		{
			auto ptr = std::make_unique<StyleInfor>();
			ptr->textColor = Color4f::Black;
			m_styleInfoArr[index] = std::move(ptr);
		}
		return m_styleInfoArr[index];
	}

	/*WidgetUniquePtr Widget::removeChildren(Widget* children)
	{
		auto i = m_childWidgets.begin();
		for (; i != m_childWidgets.end(); i++)
		{
			if ((*i).get() == children)
			{
				auto p = std::move(*i);
				p->setParent(nullptr);
				m_childWidgets.erase(i);
				return p;
			}
		}
		return nullptr;
	}
	*/

	/*void Widget::addChildren(WidgetUniquePtr&& children)
	{
		m_childWidgets.push_back(std::forward<WidgetUniquePtr>(children));
	}*/

	void Widget::draw(IRender* render, const Matrix4X4& transform)
	{

	}

	void Widget::visit(IRender* render, bool parent_change_transfrom_mat)
	{
		//更新矩阵信息
		bool is_change = this->updateMat(parent_change_transfrom_mat);

		//渲染自己
		this->draw(render, m_transformMat);

		//渲染字节点
		if (!m_childrenList.empty())
		{
			for (auto& child : m_childrenList)
			{
				if (child->isVisible())
				{
					child->visit(render, is_change);
				}
			}
		}
	}

	Vector2 Widget::getPosition() const
	{
		return m_geometry.getBottomLeft();
	}

	void Widget::setPosition(const Vector2& pos)
	{
		this->move(pos);
	}

	bool Widget::updateMat(bool parent_change)
	{
		if (parent_change || m_isChangeMat)
		{
			DirectX::XMMATRIX translation = DirectX::XMMatrixTranslation(m_geometry.getLeft(), m_geometry.getBottom(), 0.0f);
			DirectX::XMMATRIX parent = getParentMat();
			//计算世界矩阵  父节点矩阵 * 平移
			this->m_transformMat = parent * translation;
			m_isChangeMat = false;
			return true;
		}
		return false;
	}

	Widget* Widget::getActiveSibling() const
	{
		auto p = getParent();
		if (p)
		{
			for (auto& c : p->m_childrenList)
			{
				if (c->isActive())
				{
					return c;
				}
			}
		}

		return nullptr;
	}

	const Matrix4X4& Widget::getParentMat()
	{
		auto p = getParent();
		if (p)
		{
			return p->m_transformMat;
		}
		return Matrix4X4::IdentityMat;
	}

	void Widget::moveToFront()
	{
		auto p = getParent();
		if (!p)
		{
			if (!isActive())
			{
				EventWidgetActive e(this, nullptr);
				this->onActiveEvent(&e);
			}
			return;
		}

		p->moveToFront();

		if (!this->isActive())
		{
			auto active_c = this->getActiveSibling();
			if (active_c)
			{
				EventWidgetActive e(this, active_c);
				active_c->onDeactiveEvent(&e);
				this->onActiveEvent(&e);
			}
			else
			{
				EventWidgetActive e(this, nullptr);
				this->onActiveEvent(&e);
			}
		}

		p->removeChildren(this);
		p->addChildren(this);

		return;
	}


	void Widget::captureFocus()
	{
		auto currentCapture = getUiCore()->getInputCaptureWidget();
		if (this != currentCapture)
		{
			if (currentCapture)
			{
				currentCapture->setFocuse(false);
			}
			this->setFocuse(true);
		}
	}

	void Widget::releaseFocus()
	{
		auto currentCapture = getUiCore()->getInputCaptureWidget();
		if (currentCapture != this)
		{
			return;
		}

		this->setFocuse(false);

		return;
	}


	const Widget::StyleInfor* Widget::getStyleInfor() const
	{
		auto p = getStyleInforByState(m_widgetState);
		if (p)
		{
			return p;
		}
		return m_styleInfoArr[(int)Widget::WidgetState::Normal].get();
	}

	const Widget::StyleInfor* Widget::getStyleInforByState(WidgetState state)const
	{
		const auto& P = m_styleInfoArr[(int)state];
		return P.get();
	}

	void Widget::setCurrentWidgetState(WidgetState state)
	{
		if (m_widgetState != state)
		{
			m_lastWidgetState = m_widgetState;
			m_widgetState = state;
			this->onWidgetStateChange();
		}
	}

	Widget::WidgetState Widget::getCurrentWidgetState() const
	{
		return m_widgetState;
	}


	Widget* Widget::create(Widget* parent /*= nullptr*/)
	{
		auto p = makeWidgetPtr(parent);
		if (p && p->init())
		{
			if (p->getParent()) p->getParent()->addChildren(p);
			return p;
		}
		return nullptr;
	}

	Widget::~Widget()
	{
	}


	void Widget::setBackgroundImage(std::unique_ptr<Scale9Image> image, WidgetState state /*= WidgetState::Normal*/)
	{
		const auto& p = this->getStyleInfoPtr(state);
		p->backgroundImage = std::move(image);
		p->backgroundImage->setDisplaySize(m_geometry.getSize());
		onWidgetStyleChange();
	}

	void Widget::setBackgroundImage(const SpriteFrameSharedPtr& sprite_frame, Rect cap /*= Rect::Zero*/, WidgetState state /*= WidgetState::Normal*/)
	{
		this->setBackgroundImage(Scale9Image::createUniquePtr(sprite_frame, cap), state);
	}

	void Widget::setBackgroundImage(const std::wstring& file_name, Rect cap /*= Rect::Zero*/, WidgetState state /*= WidgetState::Normal*/)
	{
		this->setBackgroundImage(Scale9Image::createUniquePtr(file_name, cap), state);
	}

	void Widget::setFont(const Font& font, WidgetState state /*= WidgetState::Normal*/)
	{
		const auto& p = this->getStyleInfoPtr(state);
		p->textFont = font;
		this->onWidgetStyleChange();
	}

	void Widget::setTextColor(const Color4f& color, WidgetState state /*= WidgetState::Normal*/)
	{
		const auto& p = this->getStyleInfoPtr(state);
		p->textColor = color;
		this->onWidgetStyleChange();
	}

	void Widget::setEnabled(bool enabled)
	{
		m_isEnabled = enabled;
		if (!enabled)
		{
			this->setCurrentWidgetState(WidgetState::Disabled);
		}
		else
		{
			this->setCurrentWidgetState(WidgetState::Normal);
		}
	}

	bool Widget::isEnabled() const
	{
		return m_isEnabled;
	}

	void Widget::setMousePressEventListener(const MouseEventCallback& call)
	{
		m_mousePressEventCall = call;
	}

	void Widget::setMouseReleaseEventListener(const MouseEventCallback& call)
	{
		m_mouseReleaseEventCall = call;
	}

	void Widget::setMouseMoveEventListener(const MouseEventCallback& call)
	{
		m_mouseMoveEventCall = call;
	}

	void Widget::setMouseBoubleClickedEventListener(const MouseEventCallback& call)
	{
		m_mouseDoubleClickedEventCall = call;
	}

	Widget* Widget::getChildAtPos(const Vector2& pos, const bool allowDisable)
	{
		if (m_childrenList.size() == 0)
		{
			return this;
		}
		for (auto& w : m_childrenList)
		{
			if (w)
			{
				if (!allowDisable && !w->isEnabled())
				{
					return nullptr;
				}
				Rect rect;
				rect.setBottomLeft(w->getAbsPos());
				rect.setSize(w->getSize());
				if (rect.containPoint(pos))
				{
					return w->getChildAtPos(pos, allowDisable);
				}
			}
		}

		return nullptr;
	}

	void Widget::move(float x, float y)
	{
		this->move(Vector2(x, y));
	}

	void Widget::move(const Vector2& pos)
	{
		if (pos == m_geometry.getBottomLeft())
		{
			return;
		}
		auto old = m_geometry.getBottomLeft();
		m_geometry.moveTo(pos);
		m_isChangeMat = true;
		EventWidgetMove e(old, m_geometry.getBottomLeft());
		//触发窗口移动事件
		this->onMoveEvent(&e);
	}


	Vector2 Widget::getAbsPos() const
	{
		auto p = getParent();
		if (p)
		{
			auto pos = p->getAbsPos();
			return pos + m_geometry.getBottomLeft();
		}
		return m_geometry.getBottomLeft();
	}

	void Widget::setGeometry(const Rect& rect)
	{
		if (m_geometry.getBottomLeft() != rect.getBottomLeft())
		{
			EventWidgetMove e(m_geometry.getBottomLeft(), rect.getBottomLeft());
			m_geometry.setBottomLeft(rect.getBottomLeft());
			//触发窗口移动事件
			this->onMoveEvent(&e);
		}

		if (!(m_geometry.getSize() == rect.getSize()))
		{
			EventResize e(m_geometry.getSize(), rect.getSize());
			m_geometry.setSize(rect.getSize());
			this->onResizeEvent(&e);
		}

		m_isChangeMat = true;
	}

	const Rect& Widget::getGeometry() const
	{
		return m_geometry;
	}

	void Widget::resize(const Size& size)
	{
		if (m_geometry.getSize() == size)
		{
			return;
		}

		EventResize e(m_geometry.getSize(), size);
		m_geometry.setSize(size);

		this->onResizeEvent(&e);
	}

	const Size& Widget::getSize() const
	{
		return m_geometry.getSize();
	}

	bool Widget::isActive() const
	{

		bool parent_active = true;
		if (m_parent)
		{
			parent_active = m_parent->isActive();
		}

		return m_isActive && parent_active;
	}

	bool Widget::isDistributeCapturedInputs() const
	{
		return m_isDistributeCapturedInputs;
	}

	Widget* Widget::getActiveChiled() const
	{
		for (auto& w : m_childrenList)
		{
			if (w->m_hasFocus)
			{
				return w;
			}
		}

		return nullptr;
	}

	bool Widget::hasFocus() const
	{
		return m_hasFocus;
	}

	bool Widget::isVisible() const
	{
		return m_isVisible;
	}

	void Widget::hide()
	{
		m_isVisible = false;
	}


	void Widget::show()
	{
		m_isVisible = true;
	}

	Camera* Widget::getCamera() const
	{
		return m_camera;
	}

	void Widget::setCamera(Camera* camera)
	{
		m_camera = camera;
	}

	void Widget::setFocuse(bool focuse /*= true*/)
	{
		if (focuse == m_hasFocus)
		{
			return;
		}

		m_uiCore->setInputCaptureWidget(focuse ? this : nullptr);

		if (m_hasFocus && !focuse)
		{
			EventFocus e(EventFocus::EventType::FocusOut);
			this->onFocusOutEvent(&e);
		}
		else if (!m_hasFocus && focuse)
		{
			EventFocus e(EventFocus::EventType::FocusIn);
			this->onFocusInEvent(&e);
		}

		m_hasFocus = focuse;

	}

	Widget::FocusPolicy Widget::getFocusPolicy() const
	{
		return m_focusPolicy;
	}

	void Widget::setFocusPolicy(FocusPolicy policy)
	{
		m_focusPolicy = policy;
	}

	UiCore* Widget::getUiCore() const
	{
		return m_uiCore;
	}

	bool Widget::init()
	{
		if (!Object<Widget>::init())
		{
			return false;
		}

		//设置风格
		auto style = std::make_unique<StyleInfor>();
		style->textColor = Color4f::Black;
		m_styleInfoArr[(int)WidgetState::Normal] = std::move(style);

		//设置窗口大小
		this->resize(Size(getDefultWidth(), getDefultHeight()));

		return true;
	}
}


